import 'package:dio/dio.dart';
import 'package:logger/logger.dart';
import 'auth_ceptor.dart';
import 'log_ceptor.dart';
import 'retry_connect_reptor.dart';

class HttpManager {
  static final HttpManager _instance = HttpManager._internal();
  late Dio _dio;
  final Logger _logger = Logger();
  final CancelToken _cancelToken = CancelToken();

  factory HttpManager() => _instance;

  HttpManager._internal() {
    // 初始化Dio
    _dio = Dio(BaseOptions(
      baseUrl: 'https://cloud.aohaidigitalpower.com/',
      connectTimeout: const Duration(seconds: 15),
      receiveTimeout: const Duration(seconds: 15),
      sendTimeout: const Duration(seconds: 10),
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
      },
    ));

    // 添加拦截器
    _dio.interceptors.addAll([
      LoggingInterceptor(_logger),
      AuthInterceptor(),
      RetryOnConnectionChangeInterceptor(),
    ]);
  }

  get getDio => _dio;

  // 取消所有请求
  void cancelRequests() {
    _cancelToken.cancel('请求被主动取消');
  }

  // GET请求
  Future<dynamic> get(
      String path, {
        Map<String, dynamic>? queryParams,
        Options? options,
      }) async {
    try {
      final response = await _dio.get(
        path,
        queryParameters: queryParams,
        options: options,
        cancelToken: _cancelToken,
      );
      return _handleResponse(response);
    } on DioException catch (e) {
      throw _handleError(e);
    }
  }

  // POST请求
  Future<dynamic> post(
      String path, {
        dynamic data,
        Map<String, dynamic>? queryParams,
        Options? options,
      }) async {
    try {
      final response = await _dio.post(
        path,
        data: data,
        queryParameters: queryParams,
        options: options,
        cancelToken: _cancelToken,
      );
      return _handleResponse(response);
    } on DioException catch (e) {
      throw _handleError(e);
    }
  }

  // 文件上传
  Future<dynamic> upload(
      String path, {
        required String filePath,
        Map<String, dynamic>? formData,
        ProgressCallback? onSendProgress,
        Options? options,
      }) async {
    try {
      FormData data = FormData.fromMap({
        ...?formData,
        'file': await MultipartFile.fromFile(filePath),
      });

      final response = await _dio.post(
        path,
        data: data,
        options: options,
        cancelToken: _cancelToken,
        onSendProgress: onSendProgress,
      );
      return _handleResponse(response);
    } on DioException catch (e) {
      throw _handleError(e);
    }
  }

  // 文件下载
  Future<dynamic> download(
      String urlPath,
      String savePath, {
        ProgressCallback? onReceiveProgress,
        Options? options,
      }) async {
    try {
      final response = await _dio.download(
        urlPath,
        savePath,
        options: options,
        cancelToken: _cancelToken,
        onReceiveProgress: onReceiveProgress,
      );
      return _handleResponse(response);
    } on DioException catch (e) {
      throw _handleError(e);
    }
  }

  // 处理响应
  dynamic _handleResponse(Response response) {
    // 根据业务需求处理响应数据
    if (response.statusCode == 200) {
      return response.data;
    } else {
      throw ApiException(
        code: response.statusCode,
        message: response.data['message'] ?? '请求失败',
      );
    }
  }

  // 错误处理
  Exception _handleError(DioException e) {
    switch (e.type) {
      case DioExceptionType.connectionTimeout:
      case DioExceptionType.sendTimeout:
      case DioExceptionType.receiveTimeout:
        return NetworkException('请求超时，请检查网络连接');
      case DioExceptionType.badResponse:
        return ApiException(
          code: e.response?.statusCode,
          message: e.response?.data['message'] ?? '服务器错误',
        );
      case DioExceptionType.cancel:
        return CancelException('请求已取消');
      case DioExceptionType.connectionError:
        return NetworkException('网络连接错误，请检查网络设置');
      default:
        return AppException('网络请求异常: ${e.message}');
    }
  }
}

// 自定义异常类
class AppException implements Exception {
  final String message;
  AppException(this.message);

  @override
  String toString() => message;
}

class NetworkException extends AppException {
  NetworkException(super.message);
}

class ApiException extends AppException {
  final int? code;

  ApiException({required this.code, required String message}) : super(message);

  @override
  String toString() => '[$code] $message';
}

class CancelException extends AppException {
  CancelException(super.message);
}